/**
 * 基于vue封装的select插件
 * @author Shanks
 */
;(function (Vue) {

  const util = {};
  ;(function (util) {
    let timeout = null;
    /**
     * 防抖方法
     * @param func
     * @param wait
     * @param immediate
     */
    util.debounce = function (func, wait = 500, immediate = false) {
      // 清除定时器
      if (timeout !== null) clearTimeout(timeout)
      // 立即执行，此类情况一般用不到
      if (immediate) {
        const callNow = !timeout
        timeout = setTimeout(() => {
          timeout = null
        }, wait)
        if (callNow) typeof func === 'function' && func()
      } else {
        // 设置定时器，当最后一次操作后，timeout不会再被清除，所以在延时wait毫秒后执行func回调方法
        timeout = setTimeout(() => {
          typeof func === 'function' && func()
        }, wait)
      }
    }
  })(util)

  ;(function (util) {
    // 判断arr是否为一个数组，返回一个bool值
    function isArray(arr) {
      return Object.prototype.toString.call(arr) === '[object Array]';
    }

    // 深度克隆
    function deepClone(obj) {
      // 对常见的“非”值，直接返回原来值
      if ([null, undefined, NaN, false].includes(obj)) return obj;
      if (typeof obj !== "object" && typeof obj !== 'function') {
        //原始类型直接返回
        return obj;
      }
      var o = isArray(obj) ? [] : {};
      for (let i in obj) {
        if (obj.hasOwnProperty(i)) {
          o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
        }
      }
      return o;
    }

    util.deepClone = deepClone;
  })(util)

  Vue.component('vue-select', {
    template: `
                  <div class="vue-s-select">
                      <input ref="input" @blur="blur" v-model="showValue" :readonly="!filterable" @input="inputChange" @click.stop="click" :placeholder="placeholder">
                      <span v-if="!remote" class="vue-s-select-icon" :class="{ up: showItem }" @click.stop="click"></span>
                      <div v-show="showItem" ref="ulContainer" class="vue-s-select-ul-container">
                          <ul v-if="showOptions.length" class="vue-s-select-ul">
                            <li @click.stop="selectItem(item)" v-for="item of showOptions" :key="item[propKey]" v-text="item[valueKey]"></li>
                          </ul>
                          <ul v-else class="vue-s-select-ul">
                            <li>暂无数据!</li>
                          </ul>
                      </div>
                  </div>
              `,
    emits: ['focus', 'blur', 'confirm', 'input'],
    props: {
      placeholder: {
        type: String,
        default: '请选择'
      },
      value: {
        type: [String, Number],
        default: ''
      },
      // 下拉选项
      options: {
        type: Array,
        default: []
      },
      // key的属性名
      propKey: {
        type: [String, Number],
        default: 'key'
      },
      // value的属性名
      valueKey: {
        type: [String, Number],
        default: 'value'
      },
      filterable: {
        type: Boolean,
        default: false
      },
      // filterable和romote同时为true，才能开启远程搜索功能，同时传入remote-method
      remote: {
        type: Boolean,
        default: false
      },
      remoteMethod: {
        type: Function
      }
    },
    data: function () {
      return {
        showItem: false,
        showValue: '',
        showOptions: []
      }
    },
    watch: {
      options: function (newVal) {
        this.showOptions = util.deepClone(newVal);
      },
      value: function () {
        this.initShowValue()
      },
      showItem: function (newVal) {
        if (!newVal) return;
        this.$nextTick(() => {
          const el = this.$refs.ulContainer;
          const parentNodeRect = this.$parentNode.getBoundingClientRect();
          el.style.width = parentNodeRect.width + 'px';
          el.style.left = parentNodeRect.left + 'px';
          el.style.top = parentNodeRect.top + parentNodeRect.height + window.scrollY + 'px';
        })
      }
    },
    created: function () {
      this.initShowValue();
      this.showOptions = util.deepClone(this.options);
    },
    mounted: function () {
      this.$parentNode = this.$refs.ulContainer.parentNode;
      document.body.appendChild(this.$refs.ulContainer);
    },
    beforeDestroy: function () {
      this.$refs.ulContainer.remove();
    },
    methods: {
      click: function () {
        this.$emit('focus');
        this.showItem = true;
        this.$nextTick(() => this.$refs.input.focus());
      },
      blur: function () {
        this.$emit('blur');
        this.showItem = false;
      },
      initShowValue: function () {
        let item = this.options.find(item => item[this.propKey] == this.value);
        if (item) {
          this.showValue = item[this.valueKey];
        } else {
          this.showValue = this.value;
        }
      },
      // 选择项
      selectItem: function (item) {
        this.$emit('confirm', item);
        this.$emit('input', item[this.propKey]);
        this.showValue = item[this.valueKey];
        this.showItem = false;
      },
      // 输入change事件
      inputChange: function () {
        util.debounce(() => {
          if (this.remote) {
            // 如果是远程搜索
            this.remoteMethod(this.showValue);
          } else {
            this.showOptions = this.options.filter(item => item[this.valueKey].indexOf(this.showValue) != -1);
          }
        })
      }
    }
  })
})(Vue);